import {
  Delete as DeleteIcon,
  Edit as EditIcon,
  Save as SaveIcon,
  Cancel as CancelIcon,
} from '@mui/icons-material';
import {
  Box,
  Button,
  Container,
  IconButton,
  List,
  ListItem,
  ListItemSecondaryAction,
  ListItemText,
  Paper,
  TextField,
  Typography,
  Snackbar,
  Alert,
} from '@mui/material';
import { Component, useCallback, useEffect, useState } from 'react';
import type { KeyboardEvent, ChangeEvent, ReactNode, FC } from 'react';

interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

// 错误边界组件
class TodoErrorBoundary extends Component<
  { children: ReactNode },
  { hasError: boolean; error: Error | null }
> {
  constructor(props: { children: ReactNode }) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, info: { componentStack: string }) {
    console.error('Todo App Error:', error, info);
  }

  render(): React.ReactElement {
    if (this.state.hasError) {
      return (
        <Box sx={{ p: 2, textAlign: 'center' }}>
          <Typography color="error" gutterBottom>
            出现了一些问题。
          </Typography>
          <Typography color="textSecondary" variant="body2" gutterBottom>
            {this.state.error?.message}
          </Typography>
          <Button
            variant="contained"
            onClick={() => this.setState({ hasError: false, error: null })}
            sx={{ mt: 1 }}
          >
            重试
          </Button>
        </Box>
      );
    }

    return <>{this.props.children}</>;
  }
}

const TodoApp: FC = () => {
  const [todos, setTodos] = useState<Todo[]>([]);
  const [newTodo, setNewTodo] = useState('');
  const [editingId, setEditingId] = useState<number | null>(null);
  const [editText, setEditText] = useState('');
  const [error, setError] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(false);

  // 错误处理函数
  const handleError = useCallback((error: unknown) => {
    const errorMessage = error instanceof Error ? error.message : '发生未知错误';
    setError(errorMessage);
  }, []);

  // 保存数据到本地存储
  const saveTodos = useCallback(
    (newTodos: Todo[]) => {
      try {
        localStorage.setItem('todos', JSON.stringify(newTodos));
      } catch (err) {
        handleError(err);
      }
    },
    [handleError],
  );

  // 从本地存储加载数据
  useEffect(() => {
    const loadTodos = () => {
      try {
        const savedTodos = localStorage.getItem('todos');
        if (savedTodos) {
          setTodos(JSON.parse(savedTodos));
        }
      } catch (err) {
        handleError(err);
      } finally {
        setIsLoading(false);
      }
    };

    loadTodos();
  }, [handleError]);

  // 添加新的待办事项
  const handleAddTodo = useCallback(() => {
    try {
      if (!newTodo.trim()) {
        throw new Error('待办事项不能为空');
      }
      const newTodos = [
        ...todos,
        {
          id: Date.now(),
          text: newTodo.trim(),
          completed: false,
        },
      ];
      setTodos(newTodos);
      saveTodos(newTodos);
      setNewTodo('');
    } catch (err) {
      handleError(err);
    }
  }, [newTodo, todos, handleError, saveTodos]);

  // 删除待办事项
  const handleDeleteTodo = useCallback(
    (id: number) => {
      try {
        const newTodos = todos.filter(todo => todo.id !== id);
        setTodos(newTodos);
        saveTodos(newTodos);
      } catch (err) {
        handleError(err);
      }
    },
    [todos, handleError, saveTodos],
  );

  // 切换待办事项的完成状态
  const handleToggleTodo = useCallback(
    (id: number) => {
      try {
        const newTodos = todos.map(todo =>
          todo.id === id ? { ...todo, completed: !todo.completed } : todo,
        );
        setTodos(newTodos);
        saveTodos(newTodos);
      } catch (err) {
        handleError(err);
      }
    },
    [todos, handleError, saveTodos],
  );

  // 开始编辑待办事项
  const handleStartEdit = useCallback(
    (todo: Todo) => {
      try {
        setEditingId(todo.id);
        setEditText(todo.text);
      } catch (err) {
        handleError(err);
      }
    },
    [handleError],
  );

  // 保存编辑后的待办事项
  const handleSaveEdit = useCallback(() => {
    try {
      if (!editText.trim()) {
        throw new Error('待办事项不能为空');
      }
      if (editingId) {
        const newTodos = todos.map(todo =>
          todo.id === editingId ? { ...todo, text: editText.trim() } : todo,
        );
        setTodos(newTodos);
        saveTodos(newTodos);
        setEditingId(null);
        setEditText('');
      }
    } catch (err) {
      handleError(err);
    }
  }, [editingId, editText, todos, handleError, saveTodos]);

  // 取消编辑
  const handleCancelEdit = useCallback(() => {
    try {
      setEditingId(null);
      setEditText('');
    } catch (err) {
      handleError(err);
    }
  }, [handleError]);

  // 处理错误关闭
  const handleCloseError = useCallback(() => {
    setError(null);
  }, []);

  // 处理键盘事件
  const handleKeyPress = useCallback(
    (event: React.KeyboardEvent<HTMLInputElement>, handler: () => void) => {
      if (event.key === 'Enter') {
        handler();
      }
    },
    [],
  );

  return (
    <TodoErrorBoundary>
      <Container maxWidth="lg">
        <Box sx={{ mt: 4, mb: 4 }}>
          <Typography variant="h4" gutterBottom>
            待办事项列表
          </Typography>

          <Paper sx={{ mb: 2, p: 2 }}>
            <Box sx={{ display: 'flex', gap: 1 }}>
              <TextField
                fullWidth
                value={newTodo}
                onChange={(e: ChangeEvent<HTMLInputElement>) => setNewTodo(e.target.value)}
                placeholder="添加新的待办事项"
                onKeyPress={(e: KeyboardEvent<HTMLInputElement>) =>
                  handleKeyPress(e, handleAddTodo)
                }
                disabled={isLoading}
              />
              <Button
                variant="contained"
                onClick={handleAddTodo}
                disabled={!newTodo.trim() || isLoading}
              >
                添加
              </Button>
            </Box>
          </Paper>

          <Paper>
            <List>
              {isLoading ? (
                <ListItem>
                  <ListItemText
                    primary="加载中..."
                    sx={{ textAlign: 'center', color: 'text.secondary' }}
                  />
                </ListItem>
              ) : todos.length === 0 ? (
                <ListItem>
                  <ListItemText
                    primary="暂无待办事项"
                    sx={{ textAlign: 'center', color: 'text.secondary' }}
                  />
                </ListItem>
              ) : (
                todos.map(todo => (
                  <ListItem key={todo.id}>
                    {editingId === todo.id ? (
                      <Box sx={{ display: 'flex', gap: 1, width: '100%' }}>
                        <TextField
                          fullWidth
                          value={editText}
                          onChange={(e: ChangeEvent<HTMLInputElement>) =>
                            setEditText(e.target.value)
                          }
                          onKeyPress={(e: KeyboardEvent<HTMLInputElement>) =>
                            handleKeyPress(e, handleSaveEdit)
                          }
                        />
                        <IconButton onClick={handleSaveEdit} color="primary">
                          <SaveIcon />
                        </IconButton>
                        <IconButton onClick={handleCancelEdit}>
                          <CancelIcon />
                        </IconButton>
                      </Box>
                    ) : (
                      <Box sx={{ display: 'flex', alignItems: 'center', width: '100%' }}>
                        <ListItemText
                          primary={todo.text}
                          sx={{
                            textDecoration: todo.completed ? 'line-through' : 'none',
                            color: todo.completed ? 'text.secondary' : 'text.primary',
                            cursor: 'pointer',
                          }}
                          onClick={() => handleToggleTodo(todo.id)}
                        />
                        <ListItemSecondaryAction>
                          <IconButton
                            edge="end"
                            onClick={() => handleStartEdit(todo)}
                            sx={{ mr: 1 }}
                          >
                            <EditIcon />
                          </IconButton>
                          <IconButton edge="end" onClick={() => handleDeleteTodo(todo.id)}>
                            <DeleteIcon />
                          </IconButton>
                        </ListItemSecondaryAction>
                      </Box>
                    )}
                  </ListItem>
                ))
              )}
            </List>
          </Paper>
        </Box>

        <Snackbar open={!!error} autoHideDuration={6000} onClose={handleCloseError}>
          <Alert onClose={handleCloseError} severity="error" sx={{ width: '100%' }}>
            {error}
          </Alert>
        </Snackbar>
      </Container>
    </TodoErrorBoundary>
  );
};

export default TodoApp;
